<?php 
/*-- Project Introduce --*/


class JCAT_JPDRWindow extends JCAT_JPDRCommander
{
	const HWND_BOTTOM = 1 ;
	const HWND_TOP = 0 ;
	const HWND_TOPMOST = -1 ;
	const HWND_NOTOPMOST = -2 ;
	
	////////////////////////////
	//  窗口显示 位置 (x,y,z)
	const SWP_ASYNCWINDOWPOS = 0x4000 ;
	// If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. 
	
	const SWP_DEFERERASE = 0x2000 ;
	// Prevents generation of the WM_SYNCPAINT message. 
	
	const SWP_DRAWFRAME = 0x0020 ;
	// Draws a frame (defined in the window's class description) around the window.
	
	const SWP_FRAMECHANGED = 0x0020 ;
	// Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed.
	
	const SWP_HIDEWINDOW = 0x0080 ;
	// Hides the window.
	
	const SWP_NOACTIVATE = 0x0010 ;
	// Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter).
	
	const SWP_NOCOPYBITS = 0x0100 ;
	// Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window is sized or repositioned.
	
	const SWP_NOMOVE = 0x0002 ;
	// 保留当前位置 ( 无视self::SetWindowPos()的参数 $nX, $nY ).
	
	const SWP_NOOWNERZORDER = 0x0200 ;
	// Does not change the owner window's position in the Z order.
	
	const SWP_NOREDRAW = 0x0008 ;
	// Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing.
	
	const SWP_NOREPOSITION = 0x0200 ;
	// Same as the SWP_NOOWNERZORDER flag.
	
	const SWP_NOSENDCHANGING = 0x0400 ;
	// Prevents the window from receiving the WM_WINDOWPOSCHANGING message.
	
	const SWP_NOSIZE = 0x0001 ;
	// 保留当前尺寸 ( 无视self::SetWindowPos()的参数 $nCX, $nCY ).
	
	const SWP_NOZORDER = 0x0004 ;
	// 保留当前 z-order ( 无视self::SetWindowPos()的参数 $nWndInsertAfter ).
	
	const SWP_SHOWWINDOW = 0x0040 ;
	// Displays the window.

	
	////////////////////////////
	//  窗口显示状态
	const SW_FORCEMINIMIZE = 11 ;
	// Windows 2000/XP: Minimizes a window, even if the thread that owns the window is not responding. This flag should only be used when minimizing windows from a different thread.
	
	const SW_HIDE = 0 ;
	// Hides the window and activates another window.
	
	const SW_MAXIMIZE = 3 ;
	// Maximizes the specified window.
	
	const SW_MINIMIZE = 6 ;
	// Minimizes the specified window and activates the next top-level window in the Z order.
	
	const SW_RESTORE = 9 ;
	// Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when restoring a minimized window.
	
	const SW_SHOW = 5 ;
	// Activates the window and displays it in its current size and position. 
	
	const SW_SHOWDEFAULT = 10 ;
	// Sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application. 
	
	const SW_SHOWMAXIMIZED = 3 ;
	// Activates the window and displays it as a maximized window.
	
	const SW_SHOWMINIMIZED = 2 ;
	// Activates the window and displays it as a minimized window.
	
	const SW_SHOWMINNOACTIVE = 7 ;
	// Displays the window as a minimized window. This value is similar to SW_SHOWMINIMIZED, except the window is not activated.
	
	const SW_SHOWNA = 8 ;
	// Displays the window in its current size and position. This value is similar to SW_SHOW, except the window is not activated.
	
	const SW_SHOWNOACTIVATE = 4 ;
	// Displays a window in its most recent size and position. This value is similar to SW_SHOWNORMAL, except the window is not actived.
	
	const SW_SHOWNORMAL = 1 ;
	// Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
	
	
	////////////////////////////
	//  常用窗口消息
	
	const WM_KEYDOWN = 0x0100 ;
	const WM_KEYUP = 0x0101 ;
	const WM_CHAR = 0x0102 ;
	const WM_COMMAND = 0x0111 ;
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	void
	 */
	public function JCAT_JPDRWindow()
	{
		try{
			$this->JCAT_JPDRCommander(new COM("JPDRWinCmd.Win")) ;
		}
		catch (Exception $e)
		{
			throw new JCAT_Exception( JCAT::CharsetToProject($e->getMessage())) ;
		}
	}
	
	
	/**
	 * 返回当前所有顶层窗口的窗口句柄
	 *
	 * @access	public
	 * @return	array
	 */
	public function GetAllTopWindows()
	{
		$this->CheckAvailable() ;
		
		$sAllTopWindows = '' ;
		$this->GetCOM()->GetAllTopWindows($sAllTopWindows) ;
		
		return explode(',',$sAllTopWindows) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	JCAT_JPDRWindowIterator
	 */
	public function CreateTopWindowIter()
	{
		return new JCAT_JPDRWindowIterator($this->GetAllTopWindows(),$this) ;
	}
	
	
	/**
	 * 返回指定窗口的所有子窗口句柄
	 *
	 * @access	public
	 * @param 	$nParentWnd		int
	 * @return	array
	 */
	public function GetAllChildWindows($nParentWnd)
	{
		$this->CheckAvailable() ;
		
		$sAllTopWindows = '' ;
		$this->GetCOM()->GetAllChildWindows($nParentWnd,$sAllTopWindows) ;
		return explode(',',$sAllTopWindows) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param 	$nParentWnd		int
	 * @return	JCAT_JPDRWindowIterator
	 */
	public function CreateChildWindowIter($nParentWnd)
	{
		return new JCAT_JPDRWindowIterator($this->GetAllChildWindows($nParentWnd),$this) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @return	void
	 */
	public function IsWindow($nWndHandle)
	{
		$this->CheckAvailable() ;
		
		$bIsWindow = false ;
		$this->GetCOM()->IsWindow($nWndHandle,$bIsWindow) ;
		return $bIsWindow ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @return	void
	 */
	public function GetTitle($nWndHandle)
	{
		$this->CheckAvailable() ;
		
		$sTitle = '' ;
		$this->GetCOM()->GetTitle($nWndHandle,$sTitle) ;
		return $sTitle? $sTitle: null ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @return	void
	 */
	public function GetClass($nWndHandle)
	{
		$this->CheckAvailable() ;
		
		$sClass = '' ;
		$this->GetCOM()->GetClass($nWndHandle,$sClass) ;
		return $sClass? $sClass: null ;
	}

	/**
	 * Description
	 *
	 * @access	public
	 * @param	$sClassName			string
	 * @param	$sTitleText=''		string
	 * @return	int
	 */
	public function FindWindow($sClassName,$sTitleText='')
	{
		$this->CheckAvailable() ;
		
		$nWndHandle = 0 ;
		$this->GetCOM()->FindWindow($sClassName,$sTitleText,$nWndHandle) ;
		return $nWndHandle? $nWndHandle: null ;
	}

	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nParentWnd			int
	 * @param	$nAfterWnd=0		int
	 * @param	$sClassName=''		string
	 * @param	$sTitleText=''		string
	 * @return	int
	 */
	public function FindWindowEx($nParentWnd,$nAfterWnd=0,$sClassName='',$sTitleText='')
	{
		$this->CheckAvailable() ;
		
		$nWndHandle = 0 ;
		$this->GetCOM()->FindWindowEx($nParentWnd,$nAfterWnd,$sClassName,$sTitleText,$nWndHandle) ;
		return $nWndHandle? $nWndHandle: null ;
	}

	/**
	 * 挖掘一个子窗口
	 *
	 * @access	public
	 * @return	int
	 */
	public function DigWindow($sParentWnd)
	{
		$arrPath = func_get_args() ;
		$nFoundWnd = array_shift($arrPath) ;
		while( $arrWndInfo=array_shift($arrPath) )
		{
			list($sClass,$sTitle) = $arrWndInfo ;
			
			$nFoundWnd = $nFoundWnd? $this->FindWindowEx($nFoundWnd,0,$sClass,$sTitle):
					$this->FindWindow($sClass,$sTitle) ;
			
			if(!$nFoundWnd)
			{
				return 0 ;
			}
		}
		
		return $nFoundWnd ;
	}
	
	/**
	 * 如果指定的窗口不属于前台进程，实际效果相当于 ::FlashWindowEx()，使窗口闪烁以提醒用户
	 * 成功返回先前的活动窗口句柄，否则返回 null
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @return	int
	 */
	public function Active($nWndHandle)
	{
		$this->CheckAvailable() ;
		
		$nOldWndHandle = 0 ;
		$this->GetCOM()->Active($nWndHandle,$nOldWndHandle) ;
		return $nOldWndHandle? $nOldWndHandle: null ;
	}
	
	/**
	 * 强制将窗口切换到前台（即使该窗口不属于前台进程）
	 * 使用了windows 未公开的 API 函数 ::SwitchToThisWindow()
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @param	$bRestore=true	bool	如果窗口已经最小化，则恢复
	 * @return	void
	 */
	public function Foreground($nWndHandle,$bRestore=true)
	{
		$this->CheckAvailable() ;
		$bRestore = $bRestore?true:false ;
		$this->GetCOM()->Foreground($nWndHandle,$bRestore?true:false) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	bool
	 */
	public function SetWindowPos($nWnd,$nWndInsertAfter,$nX,$nY,$nCX,$nCY,$nFlags)
	{
		$this->CheckAvailable() ;
		$bBool = false ;
		$this->GetCOM()->SetWindowPos($nWnd,$nWndInsertAfter,$nX,$nY,$nCX,$nCY,$nFlags,$bBool) ;
		return $bBool ;
	}

	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @param	$bTop=true		int
	 * @param	$bMost=false	int
	 * @return	bool
	 */
	public function Top($nWndHandle,$bTop=true,$bTopMost=true)
	{
		if($bTop)
		{
			$nTopPos = $bTopMost? self::HWND_TOPMOST: self::HWND_TOP ;
		}
		
		else
		{
			$nTopPos = self::HWND_NOTOPMOST ;
		}
		
		return $this->SetWindowPos($nWndHandle,$nTopPos,0,0,0,0,self::SWP_NOSIZE|self::SWP_NOMOVE) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @return	bool
	 */
	public function Show($nWndHandle)
	{
		return $this->SetWindowPos($nWndHandle,0,0,0,0,0,self::SWP_NOSIZE|self::SWP_NOMOVE|self::SWP_NOZORDER|self::SWP_SHOWWINDOW) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @return	bool
	 */
	public function Hide($nWndHandle)
	{
		return $this->SetWindowPos($nWndHandle,0,0,0,0,0,self::SWP_NOSIZE|self::SWP_NOMOVE|self::SWP_NOZORDER|self::SWP_HIDEWINDOW) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @param	$nX				int
	 * @param	$nY				int
	 * @return	bool
	 */
	public function Move($nWndHandle,$nX,$nY)
	{
		return $this->SetWindowPos($nWndHandle,0,$nX,$nY,0,0,self::SWP_NOSIZE|self::SWP_NOZORDER) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @param	$nWidth			int
	 * @param	$nHeight		int
	 * @return	bool
	 */
	public function Size($nWndHandle,$nWidth,$nHeight)
	{
		return $this->SetWindowPos($nWndHandle,0,0,0,$nWidth,$nHeight,self::SWP_NOMOVE|self::SWP_NOZORDER) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @param	$nShowCmd		int
	 * @return	bool
	 */
	public function ShowWindow($nWndHandle,$nShowCmd)
	{
		$this->CheckAvailable() ;
		$bBool = false ;
		$this->GetCOM()->ShowWindow($nWndHandle,$nShowCmd,$bBool) ;
		return $bBool ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @return	bool
	 */
	public function Max($nWndHandle)
	{
		return $this->ShowWindow($nWndHandle,self::SW_MAXIMIZE) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @return	bool
	 */
	public function Min($nWndHandle)
	{
		return $this->ShowWindow($nWndHandle,self::SW_MINIMIZE) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nWndHandle		int
	 * @return	bool
	 */
	public function Restore ($nWndHandle)
	{
		return $this->ShowWindow($nWndHandle,self::SW_RESTORE) ;
	}


	/**
	 * 向窗口发送windows消息，返回是否成功
	 *
	 * @access	public
	 * @param	$nWnd			int
	 * @param	$nMsg			int
	 * @param	$nWParam=0		int
	 * @param	$nWParam=0		int
	 * @return	bool
	 */
	public function PostMessage($nWnd,$nMsg,$nWParam=0,$nLParam=0)
	{
		$this->CheckAvailable() ;
		
		$bRet = false ;
		$this->GetCOM()->PostMessage($nWnd,$nMsg,$nWParam,$nLParam,$bRet) ;
		return $bRet ;
	}

	/**
	 * 向窗口发送windows消息，等待并返回窗口处理结果
	 *
	 * @access	public
	 * @param	$nWnd			int
	 * @param	$nMsg			int
	 * @param	$nWParam=0		int
	 * @param	$nWParam=0		int
	 * @return	int
	 */
	public function SendMessage($nWnd,$nMsg,$nWParam=0,$nLParam=0)
	{
		$this->CheckAvailable() ;
		
		$nRes = 0 ;
		$this->GetCOM()->SendMessage($nWnd,$nMsg,$nWParam,$nLParam,$nRes) ;
		return $nRes ;
	}

	/**
	 * 向窗口发送  WM_DESTROY 和 WM_NCDESTROY 消息
	 * （该函数对其他进程创建的窗口无效） 
	 *
	 * @access	public
	 * @param	$nWnd	int
	 * @return	bool
	 */
	public function DestroyWindow($nWnd)
	{
		$this->CheckAvailable() ;
		
		$bRes = false ;
		$this->GetCOM()->DestroyWindow($nWnd,$bRes) ;
		return $bRes ;
	}


	
	/**
	 * 返回获得当前输入焦点的窗口
	 *
	 * @access	public
	 * @param	$nWnd	int
	 * @return	int
	 */
	public function GetFocus()
	{
		$this->CheckAvailable() ;
		
		$nRet = 0 ;
		$this->GetCOM()->GetFocus($nRet) ;
		return $nRet ;
	}
	
	/**
	 * 将一个窗口设置为 当前输入的焦点，并返回此前的焦点窗口
	 *
	 * @access	public
	 * @param	$nWnd	int
	 * @return	int
	 */
	public function SetFocus($nWnd)
	{
		$this->CheckAvailable() ;
		
		$nRet = 0 ;
		$this->GetCOM()->SetFocus($nWnd,$nRet) ;
		return $nRet ;
	}
	
	/**
	 * 返回一个数组，包含传入窗口所属的 线程ID 和 进程ID
	 *
	 * @access	public
	 * @param	$nWnd	int
	 * @return	array
	 */
	public function GetWindowThreadProcessId($nWnd)
	{
		$this->CheckAvailable() ;
		
		$nProcessId = 0 ;
		$nThreadId = 0 ;
		$this->GetCOM()->GetWindowThreadProcessId($nWnd,$nThreadId,$nProcessId) ;
		return array($nThreadId,$nProcessId) ;		
	}
	
	/**
	 * 返回 传入窗口所属的 进程ID
	 *
	 * @access	public
	 * @param	$nWnd	int
	 * @return	int
	 */
	public function GetWindowThreadId($nWnd)
	{
		list($nThreadId,) = $this->GetWindowThreadProcessId($nWnd) ;
		return $nThreadId ;	
	}
	
	/**
	 * 返回 传入窗口所属的 线程ID
	 *
	 * @access	public
	 * @param	$nWnd	int
	 * @return	int
	 */
	public function GetWindowProcessId($nWnd)
	{
		list(,$nProcessId) = $this->GetWindowThreadProcessId($nWnd) ;
		return $nProcessId ;		
	}

	/**
	 * 向窗口（可输入）发送一个字符
	 *
	 * @access	public
	 * @param	$nWnd	int
	 * @param	$Key	string,int	如果为string类型表示 ascii 码，如果为int类型表示virtual key
	 * @return	void
	 */
	public function Key($nWnd,$Key)
	{
		if( is_string($Key) )
		{
			$Key = ord($Key) ;
		}
		
		// 键入字符
		$this->SendMessage($nWnd,self::WM_CHAR,$Key,0) ;
	}

	/**
	 * 向窗口（可输入）发送一个字符
	 *
	 * @access	public
	 * @param	$nWnd				int
	 * @param	$sSentence			string
	 * @param	$nInterval=0.01		float		秒
	 * @return	void
	 */
	public function KeyString($nWnd,$sSentence,$nInterval=0.001)
	{
		$nInterval*= 1000000 ; 

		for($i=0;$i<strlen($sSentence);$i++)
		{
			$sChar = substr($sSentence,$i,1) ;
			$this->Key($nWnd,$sChar) ;

			usleep($nInterval);
		}
	}
	
	/**
	 * （无法用于其他进程的窗口）
	 *
	 * @access	public
	 * @param	$nWnd		int
	 * @param	$sText		string
	 * @return	bool
	 */
	public function SetWindowText($nWnd,$sText)
	{
		$this->CheckAvailable() ;
		
		$bRet = false ;
		$this->GetCOM()->SetWindowText($nWnd,$sText,$bRet) ;
		return $bRet ;
	}
	
	/**
	 * （无法用于其他进程的窗口）
	 *
	 * @access	public
	 * @param	$nWnd		int
	 * @return	string
	 */
	public function GetWindowText($nWnd)
	{
		$this->CheckAvailable() ;
		
		$sText = '' ;
		$this->GetCOM()->GetWindowText($nWnd,$sText) ;
		return $sText ;
	}
	
	/**
	 * 以数组格式返回指定窗口的 左、上、右、下 位置
	 *
	 * @access	public
	 * @param	$nWnd		int
	 * @return	array
	 */
	public function GetWindowRect($nWnd)
	{
		$this->CheckAvailable() ;
		
		$nLeft = $nTop = $Right = $nBottom = 0 ;
		$this->GetCOM()->GetWindowRect($nWnd,$nLeft,$nTop,$Right,$nBottom) ;
		return array($nLeft,$nTop,$Right,$nBottom) ;
	}
	
	/**
	 * 以数组格式返回指定窗口的 左、上、右、下 位置
	 *
	 * @access	public
	 * @param	$nWnd					int
	 * @param	$bScreenCoord=true		bool	屏幕坐标
	 * @return	array
	 */
	public function GetClientRect($nWnd,$bScreenCoord=true)
	{
		$this->CheckAvailable() ;
		
		$nLeft = $nTop = $Right = $nBottom = 0 ;
		$this->GetCOM()->GetClientRect($nWnd,$nLeft,$nTop,$Right,$nBottom,$bScreenCoord?true:false) ;
		return array($nLeft,$nTop,$Right,$nBottom) ;
	}
	
	/**
	 * 以数组格式返回窗口的宽和高
	 *
	 * @access	public
	 * @param	$nWnd		int
	 * @return	array
	 */
	public function GetWindowSize($nWnd)
	{
		list($nLeft,$nTop,$Right,$nBottom) = $this->GetWindowRect($nWnd) ;
		return array($Right-$nLeft,$nBottom-$nTop) ;
	}

}


class JCAT_JPDRWindowIterator extends JCAT_ArrayIterator
{
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$arrWndHandles	array
	 * @return	void
	 */
	public function JCAT_JPDRWindowIterator(array $arrWndHandles,JCAT_JPDRWindow $aJPDRCmdr)
	{
		$this->aJPDRCmdr = $aJPDRCmdr ;
		$this->JCAT_ArrayIterator($arrWndHandles) ;
	}

	/**
	 * 返回当前窗口句柄
	 * 
	 * @access	public
	 * @return	int
	 */
	public function Current()
	{ return intval(parent::Current()) ; }
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	string
	 */
	public function GetTitle()
	{
		$nWndHandle = $this->Current() ;
		return $nWndHandle? $this->aJPDRCmdr->GetTitle($nWndHandle): null ;
	}

	/**
	 * Description
	 *
	 * @access	public
	 * @return	string
	 */
	public function GetClass()
	{
		$nWndHandle = $this->Current() ;
		return $nWndHandle? $this->aJPDRCmdr->GetClass($nWndHandle): null ;
	}
		
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		JCAT_JPDRWindow
	 */
	private $aJPDRCmdr ;
}

?>